#include "pch.hpp"
#include "ScriptComponent.hpp"

using namespace Engine;
using namespace Engine::Entity;




ScriptComponent::ScriptComponent(Script::ContextPool::ptr contextPool, Script::pointer<asIScriptObject> object)
	: Component(true)
	, m_contextPool(contextPool)
	, m_object(object)
	, m_componentId(object->GetObjectType()->GetMethodIdByDecl("uint32 id()"))
	, m_attachedId(object->GetObjectType()->GetMethodIdByDecl("void attached(Entity@)"))
	, m_detachedId(object->GetObjectType()->GetMethodIdByDecl("void detached(Entity@)"))
	, m_updateId(object->GetObjectType()->GetMethodIdByDecl("void update()"))
{
	verify(m_componentId >= 0);

	// call id() from the script implementation
	storeID();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

ScriptComponent::~ScriptComponent()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////




void ScriptComponent::attached(Entity::Object* entity, const map& components)
{
	__super::attached(entity, components);

	if(m_attachedId < 0)
		return;

	auto context = m_contextPool->context();

	context->prepare(m_attachedId);
	context->setObject(m_object.get());
	context->setArgObject(0, entity);
	context->execute();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void ScriptComponent::detached(Entity::Object* entity)
{
	if(m_detachedId < 0)
		return;

	auto context = m_contextPool->context();

	context->prepare(m_detachedId);
	context->setObject(m_object.get());
	context->setArgObject(0, entity);
	context->execute();
}
///////////////////////////////////////////////////////////////////////////////////////////////////



bool ScriptComponent::requiresUpdate() const
{
	// This component requires an update in case
	// there is an implementation of the update() function
	return m_updateId >= 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void ScriptComponent::update()
{
	if(m_updateId < 0)
		return;

	auto context = m_contextPool->context();

	context->prepare(m_updateId);
	context->setObject(m_object.get());
	context->execute();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

Component::ID ScriptComponent::id() const
{
	return m_id;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void ScriptComponent::storeID()
{
	auto context = m_contextPool->context();

	context->prepare(m_componentId);
	context->setObject(m_object.get());
	context->execute();

	m_id = context->getReturnDWord();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void ScriptComponent::registerType(Script::System::ptr engine)
{
	engine->registerInterface("ScriptComponent");
	engine->registerInterfaceMethod("ScriptComponent", "uint32 id()");

	// These are NOT required to be implemented
	/*ret = engine->RegisterInterfaceMethod("ScriptComponent", "void update()"); assert(ret >= 0);
	ret = engine->RegisterInterfaceMethod("ScriptComponent", "void attached(Entity@)"); assert(ret >= 0);
	ret = engine->RegisterInterfaceMethod("ScriptComponent", "void detached(Entity@)"); assert(ret >= 0);*/
}
///////////////////////////////////////////////////////////////////////////////////////////////////
